#include "httpconn.h"

const char* HttpConn::srcDir;
std::atomic<int> HttpConn::userCount;
bool HttpConn::isET;

HttpConn::HttpConn()
{
    fd_ = -1;
    addr_ = {0};
    isClose_ = true;
}

HttpConn::~HttpConn()
{
    close();
}

// 初始化
void HttpConn::init(int socketFd, const sockaddr_in& addr)
{
    assert(socketFd > 0);
    userCount++;
    addr_ = addr;
    fd_ = socketFd;

    readBuff_.retrieveAll();
    writeBuff_.retrieveAll();
    isClose_ = false;
    LOG_INFO("Client[%d](%s:%d) in, userCount:%d", fd_, 
        getIP(), getPort(), static_cast<int>(userCount));
}

// 关闭连接
void HttpConn::close()
{
    response_.unmapFile();
    if(isClose_ == false) {
        isClose_ = true;
        userCount--;
        ::close(fd_);
        LOG_INFO("Client[%d](%s:%d) in, userCount:%d", fd_, 
        getIP(), getPort(), static_cast<int>(userCount));
    }
}

// 获取socket fd
int HttpConn::getFd() const
{
    return fd_;
}

// 获取客户端地址
struct sockaddr_in HttpConn::getAddr() const
{
    return addr_;
}

// 获取客户端IP地址
const char* HttpConn::getIP() const
{
    return inet_ntoa(addr_.sin_addr);
}

// 获取端口号
int HttpConn::getPort() const
{
    return addr_.sin_port;
}

// 获取待发送的字节数
int HttpConn::toWriteBytes() 
{
    return iov_[0].iov_len + iov_[1].iov_len;
}

// 是否使用长连接
bool HttpConn::isKeepAlive() const
{
    return request_.isKeepAlive();
}

// 从fd读取数据并存储到缓冲区
ssize_t HttpConn::read(int* saveErrno)
{
    ssize_t len = -1;
    do {
        len = readBuff_.readFd(fd_, saveErrno);
        if(len < 0) {
            break;
        }
    } while(isET);
    return len;
}

// 将数据从缓冲区写入到fd
ssize_t HttpConn::write(int* saveErrno)
{
    ssize_t len = -1;
    // 在边缘触发模式或者剩余需要写入的字节数超过1024字节, 需要循环写入数据，尽可能写入多的数据
    do {
        len = writev(fd_, iov_, iovCount_);
        if(len <= 0) {
            *saveErrno = errno;
            break;
        }

        // 数据传输完成
        if(iov_[0].iov_len + iov_[1].iov_len == 0) {
            break;
        // 第一个缓冲区数据已经全部写入
        } else if(static_cast<size_t>(len) > iov_[0].iov_len) {
            iov_[1].iov_base = (uint8_t*)iov_[1].iov_base + (len - iov_[0].iov_len);
            iov_[1].iov_len -= (len - iov_[0].iov_len);
            // 第一个缓冲区还有剩余长度(理论上不应该出现）
            if(iov_[0].iov_len) {
                writeBuff_.retrieveAll();
                iov_[0].iov_len = 0;
            }
        // 写入的数据未超过第一个缓冲区的长度
        } else {
            iov_[0].iov_base = (uint8_t*)iov_[0].iov_base + len;
            iov_[0].iov_len -= len;
            writeBuff_.retrieveAll();
        }
    } while(isET || toWriteBytes() > 1024);
    return len;
}

// 处理 HTTP 请求，解析请求内容，生成对应的 HTTP 响应到iov中
bool HttpConn::process()
{
    request_.init();
    if(readBuff_.readableBytes() <= 0) {
        return false;
    // 解析http请求
    } else if(request_.parse(readBuff_)) {
        LOG_DEBUG("Http Connection SrcDir : %s", request_.path().c_str());
        response_.init(srcDir, request_.path(), request_.isKeepAlive(), 200);
    } else {
        response_.init(srcDir, request_.path(), false, 400);
    }

    // 制作http响应
    response_.makeResponse(writeBuff_);
    // 响应头
    iov_[0].iov_base = const_cast<char*>(writeBuff_.peek());
    iov_[0].iov_len  = writeBuff_.readableBytes();
    iovCount_ = 1;
    // 文件
    if(response_.fileLen() > 0 && response_.file()) {
        iov_[1].iov_base = response_.file();
        iov_[1].iov_len  = response_.fileLen();
        iovCount_ = 2;
    }

    LOG_DEBUG("HTTP process get file : %d, %d to %d", response_.fileLen(), iovCount_, toWriteBytes());
    return true;
}